/*
 * @Author: Thomas
 * @Date: 2021-07-24 18:02:33
 * @LastEditTime: 2021-07-26 00:04:06
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: \sch_on_mcu\sch\src\sch.c
 */

#include "sch.h"

volatile static uint32_t sys_tick_clock = 0;
volatile static uint8_t systick = 0;


volatile static Task_S task[TASK_MAX];

volatile static Sys_state_S system_state;

__weak uint32_t sch_get_sys_cnt_value();
__weak uint32_t system_reboot();

/**
 * @description: sch init task struct parameters,load task related parameters
 * @param 
 * @return 0 ok ,other error
 */
int sch_init(uint32_t tick_clock,uint32_t sys_tick_cycle,idle function)
{
    int ret = 0;
    sys_tick_clock = tick_clock;
    systick = sys_tick_cycle;
    system_state.task_p = &task[0];

    for(int i = 0;i < TASK_MAX ;i++)
    {
        (system_state.task_p + i)->function = NULL;
        (system_state.task_p + i)->parameter = NULL;
        (system_state.task_p + i)->record->task_end_time = 0;
        (system_state.task_p + i)->record->task_start_time = 0;
        (system_state.task_p + i)->run_state = TASK_NONE;
       *(system_state.task_p + i)->task_name = NUL;
        (system_state.task_p + i)->time_cycle = 0;
        (system_state.task_p + i)->time_start = 0;
        (system_state.task_p + i)->time_cnt = 0;
        (system_state.task_p + i)->task_id = 0;
        (system_state.task_p + i)->feed_task_cnt = 0;
        (system_state.task_p + i)->run_mode = TASK_RUN_ONCE;
        #if ENABLE_PREEMPTIVE
        (system_state.task_p + i)->priority = Cooperative;
        #endif
        system_state.task_cnt = 0;
    }
    #if 0
    for(int i = 0;i < TASK_MAX ;i++)
    {
        task[i].function = NULL;
        task[i].parameter = NULL;
        task[i].record->task_end_time = 0;
        task[i].record->task_start_time = 0;
        task[i].run_flag =0;
        task[i].task_name = NUL;
        task[i].time_cycle = 0;
        task[i].time_start = 0;
        #if ENABLE_PREEMPTIVE
        task[i].priority = Cooperative;
        #endif

    }
    #endif

    #if ENABLE_IDLE_TASK
     system_state.idle_function = function;
    #endif


    return ret;    
}
/**
 * @description: 
 * @param {char*} task_name
 * @param {void*} parameter_p
 * @param {PREEMPTIVE_E} pree
 * @param {Entity} task_function
 * @param {PREEMPTIVE_E} para
 * @param {int} wait_time
 * @param {int} time_cycle
 * @return {*}
 */
char task_creat(char* task_name,void* parameter_p,
                #if ENABLE_PREEMPTIVE
                PREEMPTIVE_E pree,
                #endif
                Entity task_function,int wait_time,
                int time_cycle,TASK_RUN_MODE_E run_mode)
{

    char i = 0;
    char j = 0;
    for(;i < TASK_MAX ;i++)
    {
        if((system_state.task_p + i)->function == NULL)
        break;
    }
    if(i >= TASK_MAX)
    return -1;
    
    if( 
        (task_function == NULL)&&
        #if ENABLE_PREEMPTIVE
        (para > preemptive)&&
        #endif
        (run_mode > TASK_RUN_CYCLE)
    )
    return 1;

    

    if(task_name == NUL)
    {
        for(j = 0; j < 3 ; j++)
        {
            (system_state.task_p + i)->task_name[j] = *("NUL" + j);
        }
        (system_state.task_p + i)->task_name[j] = NUL;
    }
    else
    {
        j = 0;
        while((*(task_name + j)) !=NUL)
        {
            (system_state.task_p + i)->task_name[j] = *(task_name + j);
            j++;
        }
    }
    
    

    (system_state.task_p + i)->function = task_function;
    (system_state.task_p + i)->parameter = parameter_p;
    (system_state.task_p + i)->task_id = i;
    (system_state.task_p + i)->time_start = wait_time;
    (system_state.task_p + i)->time_cycle = time_cycle;
    (system_state.task_p + i)->time_cnt = time_cycle;
    (system_state.task_p + i)->run_state = TASK_WAITE;
    (system_state.task_p + i)->run_mode = run_mode;
    system_state.task_cnt ++;

    #if ENABLE_PREEMPTIVE

    (system_state.task_p + i)->priority = para;
    
    #endif


    return i;
    
}

int task_delete(char _id)
{
    if( (_id >= TASK_MAX) && (_id <= 0))
    return -1;

    if(((system_state.task_p + _id)->function == NULL) 
        && ((system_state.task_p + _id)->run_state ==TASK_NONE))
        return 1;
    (system_state.task_p + _id)->function = NULL;
    (system_state.task_p + _id)->parameter = NULL;
    (system_state.task_p + _id)->record->task_end_time = 0;
    (system_state.task_p + _id)->record->task_start_time = 0;
    (system_state.task_p + _id)->run_state = TASK_NONE;
   *(system_state.task_p + _id)->task_name = NUL;
    (system_state.task_p + _id)->time_cycle = 0;
    (system_state.task_p + _id)->time_start = 0;
    (system_state.task_p + _id)->task_id = 0;
    (system_state.task_p + _id)->run_mode = TASK_RUN_ONCE;

    #if ENABLE_PREEMPTIVE

    (system_state.task_p + _id)->priority = Cooperative;
    
    #endif

    system_state.task_cnt --;
    return 0;
}
int task_delete_all()
{
    for (int i = 0; i < TASK_MAX; i++)
    {
        task_delete(i);
    }
     return 0;
    
}


 int task_sch()
 {
    int i = 0;
    for( ;i < TASK_MAX ;i++)
    {
        if((task[i].run_state == TASK_RUN) && 
           (task[i].function != NULL)  
           #if ENABLE_PREEMPTIVE
           && (task[i].priority == Cooperative)
           #endif
           )
        {
            #if ENABLE_TASK_TIME_RECORD
            task[i].record[0].task_start_time = sch_get_sys_cnt_value();
            #endif
                    
            task[i].function(task[i].parameter);
            feed_task(i);

            #if ENABLE_TASK_TIME_RECORD
            task[i].record[0].task_end_time = sch_get_sys_cnt_value();
            #endif
        }
        else
        {
            continue;
        }
        
        if(task[i].run_mode == TASK_RUN_ONCE)
        {
            task_delete(i);
            continue;
        }
        
        task[i].run_state = TASK_WAITE;
        task[i].time_cnt = task[i].time_cycle;

    }

    #if ENABLE_IDLE_TASK
    i =0;
    for( ;i < TASK_MAX ;i++)
    {
        if(task[i].run_state == TASK_NONE)
        continue;
        
        if(task[i].time_cnt <= RUN_IDLE_TASK_TIME_INTERVAL)
        break;
    }

    if((i >= TASK_MAX) && (system_state.idle_function != NULL))
    system_state.idle_function();
    

    #endif
    
    return 0;
 }

int sys_tick_call_function()
{
    int i = 0;
    for( ;i < TASK_MAX ;i++)
    {
        if((system_state.task_p + i)->time_start != 0)
        {
          (system_state.task_p + i)->time_start-- ;
          continue;
        }
        if((task[i].run_state != TASK_NONE) && 
           (task[i].function != NULL))
        {
          
            task[i].time_cnt --;
            if(task[i].time_cnt == 0)
            {
                #if ENABLE_PREEMPTIVE
                if(task[i].priority == Cooperative)
                {
                #endif
                    task[i].run_state = TASK_RUN;
                    if(task[i].feed_task_cnt++ > MAX_TASK_TIMEOUT_CNT)
                    {
                      // report task execute timeout;
                      system_reboot();
                      
                    }
                #if ENABLE_PREEMPTIVE
                }
                else
                {
                    #if ENABLE_TASK_TIME_RECORD
                    task[i].record[0].task_start_time = sch_get_sys_cnt_value();
                    #endif
                    
                    task[i].function(task[i].parameter);

                    #if ENABLE_TASK_TIME_RECORD
                    task[i].record[0].task_end_time = sch_get_sys_cnt_value();
                    #endif

                    if(task[i].run_mode == TASK_RUN_ONCE)
                    {
                        task_delete(i);
                        continue;
                    }
        
                    task[i].run_state = TASK_WAITE;
                    task[i].time_cnt = task[i].time_cycle;

                }
                #endif

                
            }
        }
        else
        {
            continue;
        }

    }
    
    return 0;
}

void feed_task(uint8_t i)
{
  task[i].feed_task_cnt = 0;
}

extern __ATTRIBUTES void          __set_PRIMASK( unsigned long );
void task_display()
{
  int i = 0;
   __set_PRIMASK(1);//�����ж�
  for( ;i < TASK_MAX ;i++)
  {
    if(task[i].function == NULL)
      continue;
    //cliprintf("%-20s%-20s%-20s%s",Task ID, "Task name", "Cycle(ms)","Takes ");
    printf("%-30d%-30s%-30d%-30d\r\n",task[i].task_id,task[i].task_name,task[i].time_cycle,task[i].record->task_start_time-task[i].record->task_end_time);
  }
   __set_PRIMASK(0);//�����ж�
}

__weak uint32_t sch_get_sys_cnt_value()
{
    return 0;
}

__weak uint32_t system_reboot()
{
    return 0;
}